﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TableTopWidgets
{
    /// <summary>
    /// Interaction logic for RadialMenu.xaml
    /// </summary>
    public class RadialMenu : Panel
    {
        #region Orientation
        private const double DEFAULT_ANGLE = 0;
        public double Orientation
        {
            get { return (double)GetValue(OrientationProperty); }
            set { SetValue(OrientationProperty, value); }
        }
        public static readonly DependencyProperty OrientationProperty =
            DependencyProperty.Register(
                "Orientation",
                typeof(double),
                typeof(RadialMenu),
                new FrameworkPropertyMetadata(DEFAULT_ANGLE,
                    FrameworkPropertyMetadataOptions.AffectsMeasure));
        #endregion
        #region PieSize
        private const double DEFAULT_SIZE = 360;
        public double PieSize
        {
            get { return (double)GetValue(PieSizeProperty); }
            set { SetValue(PieSizeProperty, value); }
        }
        public static readonly DependencyProperty PieSizeProperty =
            DependencyProperty.Register(
                "PieSize",
                typeof(double),
                typeof(RadialMenu),
                new FrameworkPropertyMetadata(DEFAULT_SIZE,
                    FrameworkPropertyMetadataOptions.AffectsMeasure));
        #endregion
        #region MinRadius
        private const double DEFAULT_MINRADIUS = 0;
        public double MinRadius
        {
            get { return (double)GetValue(MinRadiusProperty); }
            set { SetValue(MinRadiusProperty, value); }
        }
        public static readonly DependencyProperty MinRadiusProperty =
            DependencyProperty.Register(
                "MinRadius",
                typeof(double),
                typeof(RadialMenu),
                new FrameworkPropertyMetadata(DEFAULT_MINRADIUS,
                    FrameworkPropertyMetadataOptions.AffectsMeasure));
        #endregion
        #region MaxRadius
        private const double DEFAULT_MAXRADIUS = 0;
        public double MaxRadius
        {
            get { return (double)GetValue(MaxRadiusProperty); }
            set { SetValue(MaxRadiusProperty, value); }
        }
        public static readonly DependencyProperty MaxRadiusProperty =
            DependencyProperty.Register(
                "MaxRadius",
                typeof(double),
                typeof(RadialMenu),
                new FrameworkPropertyMetadata(DEFAULT_MAXRADIUS,
                    FrameworkPropertyMetadataOptions.AffectsMeasure));
        #endregion

        public RadialMenu()
        {
        }

        protected override Size MeasureOverride(Size constraint)
        {
            autoSizeAngle();
            autoSizeInnerRadius();
            autoSizeOuterRadius();
            double maxSize = findMaxSize();

            Size finalSize = new Size(maxSize,maxSize);
            return finalSize;
        }
        protected override Size ArrangeOverride(Size arrangeSize)
        {
            double adjustedOrientation = Orientation - 90;
            double cumulativeRotations = 0;

            double maxSize = findMaxSize();
            this.Width = 2 * maxSize;
            this.Height = 2 * maxSize;

            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;

                child.Arrange(new Rect(new Point(), child.DesiredSize));

                TransformGroup transform = new TransformGroup();
                double xtranslation = 0;
                double ytranslation = 0;
                double rotationAngle = 0;
                
                //Move button to center
                xtranslation -= button.ActualWidth / 2;
                ytranslation -= button.ActualHeight / 2;
                if (button.Angle < 360)
                {
                    //Move the button up
                    double buttonHeight = button.OuterRadius - button.InnerRadius;
                    double lowerMargin = button.ActualHeight - buttonHeight;
                    double centerToBottomDistance = button.ActualHeight / 2 - lowerMargin;
                    ytranslation -= centerToBottomDistance;
                    ytranslation -= button.InnerRadius;

                    //Roate the button the appropriate amount
                    //  1.Initial Rotation
                    rotationAngle += button.Angle / 2 + adjustedOrientation;
                    //  2.Rotate for each additional button before it
                    rotationAngle += cumulativeRotations;
                    //  3.Account for the size of this button
                    cumulativeRotations += button.Angle;
                }
                //Apply the transformation
                transform.Children.Add(new TranslateTransform(xtranslation, ytranslation));
                transform.Children.Add(new RotateTransform(rotationAngle, 0, 0));

                button.RenderTransform = transform;
            }
            /* Calculate the space required for this widget */

            double firstAngle = Orientation % 360;
            firstAngle = firstAngle < 0 ? firstAngle + 360 : firstAngle;

            Size finalSize = calculateSize(firstAngle, cumulativeRotations);

            return new Size(0,0);  //I think this is a position offset
        }

        private Size calculateSize(double firstAngle, double pieSize)
        {
            double h = 0;
            double w = 0;

            //Quadrant 1: NW
            //Quadrant 2: NE
            //Quadrant 3: SE
            //Quadrant 4: SW

            return new Size(h, w); // stub
        }
        private void autoSizeAngle()
        {
            double totalSize = PieSize;
            double totAngle = CalculateTotalAngles();
            int count = NumberofDefaultButtons();
            double autoSizeAngle = 0;
            if (count != 0) autoSizeAngle = (totalSize - totAngle) / count;
            
            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;

                if (button.isAngleDefault)
                {
                    button.SetAutoSizeAngle(autoSizeAngle);
                }
            }
        }
        private void autoSizeInnerRadius()
        {
            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;
                if (button.isInnerRadiusDefault || button.InnerRadius < MinRadius)
                {
                    button.SetAutoSizeInnerRadius(MinRadius);
                }
            }
        }
        private void autoSizeOuterRadius()
        {
            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;
                if (button.isOuterRadiusDefault || (button.OuterRadius > MaxRadius && MaxRadius != DEFAULT_MAXRADIUS))
                {
                    button.SetAutoSizeOuterRadius(MaxRadius);
                }
            }
        }
        private void InvalidateAllButtons()
        {
            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;

                button.UpdateGeometry();
                button.InvalidateVisual();
            }
        }
        private double findMaxSize()
        {
            double maxSize = 0;

            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;

                child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));

                if (button.OuterRadius > maxSize) maxSize = button.OuterRadius;
            }
            return maxSize;
        }
        private double CalculateTotalAngles()
        {
            double totAngle = 0;
            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;

                if (!button.isAngleDefault) totAngle += button.Angle;
            }
            return totAngle;
        }
        private int NumberofDefaultButtons()
        {
            int count = 0;
            foreach (UIElement child in Children)
            {
                RadialButton button = child as RadialButton;
                if (button == null) continue;
                if (button.isAngleDefault)
                    count++;
            }
            return count;
        }
    }
}
